home *** CD-ROM | disk | FTP | other *** search
/ Java Developer's Companion / Java Developer's Companion.iso / Javacup / UNUAM4CS.TAR / unlimited / UNUAM4CS / XSliceVolumeFilter.java < prev    next >
Encoding:
Java Source  |  1996-05-21  |  11.6 KB  |  371 lines

  1. /*
  2.  * @(#)/XSliceVolumeFilter.java    1.4 96/03/31 by Andrew Barclay abb@nuccard.eushc.org
  3.  *
  4.  * Copyright (c) 1995 Andrew B. Barclay All Rights Reserved.
  5.  */
  6.  
  7. import java.awt.image.ColorModel ;
  8. import java.awt.image.ImageConsumer ;
  9. import java.awt.image.ImageProducer ;
  10. import java.awt.Point ;
  11. import java.awt.Rectangle ;
  12.  
  13. import SliceVolumeFilter ;
  14.  
  15. /**
  16.  * An ImageFilter class for sliceing volume images.
  17.  * This class extends the basic ImageFilter Class to extract a given
  18.  * slice of an existing Volume and provide a source for a
  19.  * new image containing just the extracted slice.  It is meant to
  20.  * be used in conjunction with a FilteredImageSource object to produce
  21.  * sliced versions of existing volumes.
  22.  *
  23.  * This one's a bear, because the image granularity is 1 pixel.  After
  24.  * endless trials (really) I've resorted to just waiting for complete
  25.  * scanlines before updating.  Random pixel delivery to the dithering
  26.  * engine produces unpredictable results.
  27.  *
  28.  * @see CropImageFilter
  29.  * @see FilteredImageSource
  30.  * @see ImageFilter
  31.  * @see SliceVolumeFilter
  32.  *
  33.  * @version    1.4 96/03/31
  34.  * @author     Andrew Barclay
  35.  */
  36.  
  37. public class XSliceVolumeFilter extends SliceVolumeFilter {
  38.     public byte dpixbyte[] ;  // byte extracted pixel buffer
  39.     public int dpixint[] ;  // int extracted pixel buffer
  40.     double szincr ;  // source z-increment for each dest. z slice
  41.     int nslices ;
  42.     int hints ;
  43.     int completecols[] ;
  44.     int completerows ;
  45.     ColorModel colormodel ;  // last colormodel (for resends)
  46.  
  47.     synchronized void dbg( String s ) {
  48.     if( false ) {
  49.         System.out.println( s ) ;
  50.     }
  51.     }
  52.  
  53.     /**
  54.      * Construct a SliceVolumeFilter that extracts a slice of the source
  55.      * Volume specified by the ul, ll and ur parameters.
  56.      * @param srcSlices[] the array of x,y positions of the source image slices
  57.      * @param volWidth the width of the source volume
  58.      * @param volHeight the height of the source volume
  59.      * @param slice the slice number to be extracted
  60.      * @param width the width of the slice to be extracted
  61.      * @param height the height of the slice to be extracted
  62.      */
  63.     public XSliceVolumeFilter( Point srcSlices[], int volWidth,
  64.         int volHeight, double slice, int width, int height ) {
  65.     super( srcSlices, volWidth, volHeight, slice, width, height ) ;
  66.     type = 'X' ;
  67.     szincr = (double)voldims[2] / (double)width ;  // usually 1.0
  68.     nslices = voldims[0] ;
  69.     hints = 0 ;
  70.     completecols = new int[height] ;
  71.     for( int i = 0 ; i < height ; i++ ) {
  72.         completecols[i] = 0 ;
  73.     }
  74.     completerows = 0 ;
  75.     }
  76.  
  77.     public void resendTopDownLeftRight( ImageProducer ip ) {
  78.     dbg( "resendTopDownLeftRight called." ) ;
  79.     if( dpixbyte != null ) {
  80.         setConsumerPixels( 0, 0, width, height, 
  81.         this.colormodel, dpixbyte, 0, width ) ;
  82.     } else if( dpixint != null ) {
  83.         setConsumerPixels( 0, 0, width, height, 
  84.         this.colormodel, dpixint, 0, width ) ;
  85.     }
  86.     }
  87.  
  88.     public void setHints( int hints ) {
  89.     this.hints = hints ;
  90.     dbg( "setHints called, COMPLETESCANLINES="+((hints&ImageConsumer.COMPLETESCANLINES)!=0)+", RANDOMPIXELORDER="+((hints&ImageConsumer.RANDOMPIXELORDER)!=0) ) ;
  91.     dbg( "SINGLEPASS="+((hints&ImageConsumer.SINGLEPASS)!=0)+", SINGLEFRAME="+((hints&ImageConsumer.SINGLEFRAME)!=0) ) ;
  92.     }
  93.  
  94.     /**
  95.      * Decide if we can deliver complete scanlines before sending
  96.      * pixels to consumer.
  97.      */
  98.     public void setConsumerPixels( int sx, int sy, int sw, int sh,
  99.               ColorModel colormodel, byte spix[], int soff,
  100.               int sscansize ) {
  101.     if( sw != width ) {
  102.         /*
  103.          * The code below doesn't work and is very cpu intensive.
  104.          * I suspect that the API cannot handle RANDOMPIXELORDER.
  105.          *
  106.          * Random delivery code:
  107.          * In this case, clear all other hints so the consumer
  108.          * will request a resend.  The next time through we
  109.          * should have complete scanlines, etc.
  110.          *
  111.         hints = ImageConsumer.RANDOMPIXELORDER ;
  112.         consumer.setHints( hints ) ;
  113.         consumer.setPixels( sx, sy, sw, sh, colormodel,
  114.         spix, soff, sscansize ) ;
  115.          */
  116.  
  117.         dbg( "g.setConsumerPixels.byte: sx="+sx+" sy="+sy+" sw="+sw+" sh="+sh+"." ) ;
  118.         for( int y = sy ; y < sy+sh ; y++ ) {
  119.         completecols[y] += sw ;
  120.         if( completecols[y] == width ) {
  121.             completerows++ ;
  122.  
  123.             /*
  124.              * This doesn't work either -- just get a blank image,
  125.              * though I'm delivering real data to the consumer???
  126.              *
  127.             // spit complete line out.
  128.             int p = y*width ;
  129.             byte max = spix[p++] ;
  130.             for( int i = 1 ; i < width ; i++ ) {
  131.             if( spix[p] > max ) max = spix[p] ;
  132.             p++ ;
  133.             }
  134.             System.out.println( "completed line "+y+" max="+max+"." ) ;
  135.             //consumer.setHints( COMPLETESCANLINES|SINGLEPASS|SINGLEFRAME ) ;
  136.             consumer.setHints( hints ) ;
  137.             consumer.setPixels( 0, y, width, 1, colormodel,
  138.             spix, soff, sscansize ) ;
  139.             */
  140.         }
  141.         }
  142.  
  143.         /*
  144.          * Full buffering is the only way it works reliably.
  145.          */
  146.         if( completerows == height ) {
  147.         consumer.setHints( hints ) ;
  148.         consumer.setPixels( 0, 0, width, height, 
  149.             colormodel, dpixbyte, 0, width ) ;
  150.         }
  151.     } else {
  152.         dbg( "setConsumerPixels.byte: sw==width="+sw+".") ;
  153.         consumer.setHints( hints ) ;
  154.         consumer.setPixels( sx, sy, sw, sh, colormodel,
  155.         spix, soff, sscansize ) ;
  156.     }
  157.     }
  158.  
  159.     public void setConsumerPixels( int sx, int sy, int sw, int sh,
  160.               ColorModel colormodel, int spix[], int soff,
  161.               int sscansize ) {
  162.     if( sw != width ) {
  163.         dbg( "g.setConsumerPixels.int: sx="+sx+" sy="+sy+" sw="+sw+" sh="+sh+"." ) ;
  164.         for( int y = sy ; y < sy+sh ; y++ ) {
  165.         completecols[y] += sw ;
  166.         if( completecols[y] == width ) {
  167.             completerows++ ;
  168.         }
  169.         }
  170.  
  171.         /*
  172.          * Full buffering is the only way it works reliably.
  173.          */
  174.         if( completerows == height ) {
  175.         consumer.setHints( hints ) ;
  176.         consumer.setPixels( 0, 0, width, height, 
  177.             colormodel, dpixint, 0, width ) ;
  178.         }
  179.     } else {
  180.         dbg( "setConsumerPixels.int: sw==width="+sw+".") ;
  181.         consumer.setHints( hints ) ;
  182.         consumer.setPixels( sx, sy, sw, sh, colormodel,
  183.         spix, soff, sscansize ) ;
  184.     }
  185.     }
  186.  
  187.     /**
  188.      * Determine if the delivered pixels intersect the slice to
  189.      * be extracted and pass through only that subset of pixels that
  190.      * appear in the output slice.
  191.      */
  192.     public void setPixels( int sx, int sy, int sw, int sh,
  193.               ColorModel colormodel, byte spix[], int soff,
  194.               int sscansize ) {
  195.     long ct = System.currentTimeMillis() ;
  196.     Rectangle sr = new Rectangle( sx, sy, sw, sh ) ;
  197.     int sz1 = firstZSlice( sr ) ;  // first z-slice intersecting region
  198.     int sz2 = lastZSlice( sr ) ;  // last z-slice intersecting region
  199.     this.colormodel = colormodel ;
  200.     /*
  201.     dbg( "sr="+sr+" sz1="+sz1+" sz2="+sz2 ) ;
  202.     dbg( "off="+soff+" scansize="+sscansize+" type="+type+" slice="+slice ) ;
  203.     */
  204.  
  205.     // implement this generally later -- for now, just take orthogonal
  206.     // slices.
  207.     int islice = (int)( 0.5 + slice ) ;
  208.     if( islice >= 0 && islice < nslices ) {
  209.         // fix later: the allocation should depend on szincr too...
  210.         if( dpixbyte == null ) {
  211.         dpixbyte = new byte[width*height] ;
  212.         }
  213.         double sz ;
  214.         int ncols = 0 ;
  215.         int lastxstart = 0, lastystart = 0, lastyend = 0 ;
  216.  
  217.         for( sz = -0.5*szincr + sz1 ; sz < (-0.5 + sz2) ; sz += szincr ) {
  218.         // z-coords in source correspond to x-coords in dest.
  219.         int xstart = (int)( 0.5 + sz/szincr ) ;
  220.         int isz = (int)( 0.5 + sz ) ;
  221.         int x1 = srcSlices[isz].x + islice ;
  222.         int y1 = srcSlices[isz].y ;
  223.         if( sy < (y1+height) && (sy+sh) > y1 &&
  224.             sx <= x1 && (sx+sw) > x1 ) {
  225.  
  226.             int ystart = (y1>=sy) ? 0 : sy-y1 ;
  227.             int yend = ((y1+height)>(sy+sh)) ? (sy+sh-y1) : height ;
  228.             int is = soff + (x1-sx) + (y1+ystart-sy)*sscansize ;
  229.             int id = xstart + ystart*width ;
  230.  
  231.             // Copy portion of column from the source to dest.
  232.             for( int dy = ystart ; dy < yend ; dy++ ) {
  233.             dpixbyte[id] = spix[is] ;
  234.             is += sscansize ;
  235.             id += width ;
  236.             }
  237.  
  238.             if( ncols == 0 ) {
  239.             // initialize these.
  240.             lastxstart = xstart ;
  241.             lastystart = ystart ;
  242.             lastyend = yend ;
  243.             ncols = 1 ;
  244.             } else if( lastystart != ystart || lastyend != yend ) {
  245.             // spit out columns up to this column.
  246.             setConsumerPixels( lastxstart, lastystart, ncols,
  247.                 lastyend-lastystart, colormodel, dpixbyte,
  248.                 0, width ) ;
  249.  
  250.             lastxstart = xstart ;
  251.             lastystart = ystart ;
  252.             lastyend = yend ;
  253.             ncols = 1 ;
  254.             } else {
  255.             ncols++ ;
  256.             }
  257.         } else if( ncols > 0 ) {
  258.             // probably skipping a z-slice, spit out columns up
  259.             // to this column.
  260.             setConsumerPixels( lastxstart, lastystart, ncols,
  261.             lastyend-lastystart, colormodel, dpixbyte,
  262.             0, width ) ;
  263.             ncols = 0 ;
  264.         }
  265.         }
  266.  
  267.         // spit out remaining columns.
  268.         if( ncols > 0 ) {
  269.         setConsumerPixels( lastxstart, lastystart, ncols,
  270.             lastyend-lastystart, colormodel, dpixbyte,
  271.             0, width ) ;
  272.  
  273.         dbg( "byte time= "+(System.currentTimeMillis()-ct)+" ms.\n" ) ;
  274.         dbg( "xslice="+islice+" sr="+sr+" sz1="+sz1+" sz2="+sz2 ) ;
  275.         dbg( "lastxstart="+lastxstart+" ncols="+ncols ) ;
  276.         dbg( "lastystart="+lastystart+" lastyend="+lastyend ) ;
  277.         }
  278.     }
  279.     }
  280.     
  281.     public void setPixels( int sx, int sy, int sw, int sh,
  282.               ColorModel colormodel, int spix[], int soff,
  283.               int sscansize ) {
  284.     long ct = System.currentTimeMillis() ;
  285.     Rectangle sr = new Rectangle( sx, sy, sw, sh ) ;
  286.     int sz1 = firstZSlice( sr ) ;  // first z-slice intersecting region
  287.     int sz2 = lastZSlice( sr ) ;  // last z-slice intersecting region
  288.     this.colormodel = colormodel ;
  289.     /*
  290.     dbg( "sr="+sr+" sz1="+sz1+" sz2="+sz2 ) ;
  291.     dbg( "off="+soff+" scansize="+sscansize+" type="+type+" slice="+slice ) ;
  292.     */
  293.  
  294.     // implement this generally later -- for now, just take orthogonal
  295.     // slices.
  296.     int islice = (int)( 0.5 + slice ) ;
  297.     if( islice >= 0 && islice < nslices ) {
  298.         // fix later: the allocation should depend on szincr too...
  299.         if( dpixint == null ) {
  300.         dpixint = new int[width*height] ;
  301.         }
  302.         double sz ;
  303.         int ncols = 0 ;
  304.         int lastxstart = 0, lastystart = 0, lastyend = 0 ;
  305.  
  306.         for( sz = -0.5*szincr + sz1 ; sz < (-0.5 + sz2) ; sz += szincr ) {
  307.         // z-coords in source correspond to x-coords in dest.
  308.         int xstart = (int)( 0.5 + sz/szincr ) ;
  309.         int isz = (int)( 0.5 + sz ) ;
  310.         int x1 = srcSlices[isz].x + islice ;
  311.         int y1 = srcSlices[isz].y ;
  312.         if( sy < (y1+height) && (sy+sh) > y1 &&
  313.             sx <= x1 && (sx+sw) > x1 ) {
  314.  
  315.             int ystart = (y1>=sy) ? 0 : sy-y1 ;
  316.             int yend = ((y1+height)>(sy+sh)) ? (sy+sh-y1) : height ;
  317.             int is = soff + (x1-sx) + (y1+ystart-sy)*sscansize ;
  318.             int id = xstart + ystart*width ;
  319.  
  320.             // Copy portion of column from the source to dest.
  321.             for( int dy = ystart ; dy < yend ; dy++ ) {
  322.             dpixint[id] = spix[is] ;
  323.             is += sscansize ;
  324.             id += width ;
  325.             }
  326.  
  327.             if( ncols == 0 ) {
  328.             // initialize these.
  329.             lastxstart = xstart ;
  330.             lastystart = ystart ;
  331.             lastyend = yend ;
  332.             ncols = 1 ;
  333.             } else if( lastystart != ystart || lastyend != yend ) {
  334.             // spit out columns up to this column.
  335.             setConsumerPixels( lastxstart, lastystart, ncols,
  336.                 lastyend-lastystart, colormodel, dpixint,
  337.                 0, width ) ;
  338.  
  339.             lastxstart = xstart ;
  340.             lastystart = ystart ;
  341.             lastyend = yend ;
  342.             ncols = 1 ;
  343.             } else {
  344.             ncols++ ;
  345.             }
  346.         } else if( ncols > 0 ) {
  347.             // probably skipping a z-slice, spit out columns up
  348.             // to this column.
  349.             setConsumerPixels( lastxstart, lastystart, ncols,
  350.             lastyend-lastystart, colormodel, dpixint,
  351.             0, width ) ;
  352.             ncols = 0 ;
  353.         }
  354.         }
  355.  
  356.         // spit out remaining columns.
  357.         if( ncols > 0 ) {
  358.         setConsumerPixels( lastxstart, lastystart, ncols,
  359.             lastyend-lastystart, colormodel, dpixint,
  360.             0, width ) ;
  361.  
  362.         dbg( "int time= "+(System.currentTimeMillis()-ct)+" ms.\n" ) ;
  363.         dbg( "xslice="+islice+" sr="+sr+" sz1="+sz1+" sz2="+sz2 ) ;
  364.         dbg( "lastxstart="+lastxstart+" ncols="+ncols ) ;
  365.         dbg( "lastystart="+lastystart+" lastyend="+lastyend ) ;
  366.         }
  367.     }
  368.     }
  369.     
  370. }
  371.